package cpu;

import cpu.instr.all_instrs.InstrFactory;
import cpu.instr.all_instrs.Instruction;
import cpu.registers.EIP;
import cpu.registers.Register;
import transformer.Transformer;

public class CPU {

    static Transformer transformer = new Transformer();
    static MMU mmu = MMU.getMMU();

    boolean on = true;
    String state = "00";
    Instruction instruction;


    /**
     * execInstr specific numbers of instructions
     *
     * @param number numbers of instructions(指令数)
     */
    public int execInstr(long number) {
        // 执行过的指令的总长度
        int totalLen = 0;
        while (number > 0) {
            int instrLength = execInstr();
            if (0 > instrLength) {
                break;
            } else {
                number--;
                totalLen += instrLength;//TODO:获取指令总长
                ((EIP) CPU_State.eip).plus(instrLength);//TODO:EIP指向下一条指令的空间(逻辑地址，用mmu读取)
            }
        }
        return totalLen;
    }

    /**
     * execInstr a single instruction according to eip value
     */
    private int execInstr() {
        String eip = CPU_State.eip.read();
        int len = decodeAndExecute(eip);
        return len;
    }

    private int decodeAndExecute(String eip) {
        int opcode = instrFetch(eip, 1);//TODO:获取指令编码
//        instruction = InstrFactory.getInstr(opcode);//TODO:取指令
//        assert instruction != null;

        //exec the target instruction
        int len = instruction.exec(opcode);//TODO:返回该指令占储存空间总长度
        return len;


    }

    /**
     * @param eip
     * @param length opcode的字节数，本作业只使用单字节opcode
     * @return 获取指令
     */
    public static int instrFetch(String eip, int length) {
        /**
         * 目前默认只有一个数据段
         */
        Register cs = CPU_State.cs;

        // length = length * 8  一个字节8位
        String opcode = String.valueOf(mmu.read(cs.read() + eip, length * 8));
        return Integer.parseInt(transformer.binaryToInt(opcode));
    }

    public void execUntilHlt() {
        // TODO ICC
        on = true;
        state = "00";
        while (on) {
            switch (state) {
                case "11": interrupt();
                case "10": execute();
                case "01": indirect();
                case "00": fetch();
            }
        }
    }

    private void fetch() {
        String eip = CPU_State.eip.read();
        int opcode = instrFetch(eip, 1);//TODO:获取指令编码
        instruction = InstrFactory.getInstr(opcode);//TODO:取指令
        assert instruction != null;
        //exec the target instruction
        String instr = instruction.fetchInstr(eip,opcode);
        if (instr.equals("11110100"))
            on = false;
        state = "10";
    }
    private void indirect(){
        //在指令中实现间址
        state = "10";
    }
    private void execute(){
        execInstr(1);
        state = "00";
    }
    private void interrupt(){}
}

